package com.qzdatasoft.autoconfigure.ratelimit;

import com.qzdatasoft.HierarchicalRateLimiter;
import com.qzdatasoft.ratelimit.adapter.ClientInfoExtractor;
import com.qzdatasoft.ratelimit.adapter.RateLimitRuleCacheManager;
import com.qzdatasoft.ratelimit.adapter.RateLimitRuleQueryProvider;
import com.qzdatasoft.ratelimit.adapter.impl.DefaultClientInfoExtractor;
import com.qzdatasoft.ratelimit.adapter.impl.DefaultRateLimitRuleQueryProvider;
import com.qzdatasoft.ratelimit.core.RateLimitFilter;
import com.qzdatasoft.ratelimit.po.RateLimitRulePo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * Nginx风格漏桶限流自动配置类
 */
@Configuration
@EnableConfigurationProperties(RateLimitProperties.class)
@ConditionalOnProperty(name = "ratelimit.enabled", havingValue = "true", matchIfMissing = true)
public class RateLimitAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public ClientInfoExtractor clientInfoExtractor() {
        return new DefaultClientInfoExtractor();
    }

    @Bean
    @ConditionalOnMissingBean
    public RateLimitRuleQueryProvider rateLimitRuleQueryProvider(RateLimitProperties properties) {
        return new DefaultRateLimitRuleQueryProvider(properties.getRules());
    }
    
    @Bean
    @ConditionalOnMissingBean
    public RateLimitRuleCacheManager rateLimitRuleCacheManager(
            RateLimitRuleQueryProvider queryProvider,ClientInfoExtractor clientInfoExtractor) {
        return new RateLimitRuleCacheManager(queryProvider, clientInfoExtractor);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "ratelimit.enabled", havingValue = "true", matchIfMissing = true)
    public HierarchicalRateLimiter hierarchicalRateLimiter(RateLimitProperties properties) {
        return new HierarchicalRateLimiter();
    }

    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean<RateLimitFilter> rateLimitFilter(
            HierarchicalRateLimiter hierarchicalRateLimiter,
            ClientInfoExtractor clientInfoExtractor,
            RateLimitProperties properties) {
        FilterRegistrationBean<RateLimitFilter> registrationBean = new FilterRegistrationBean<>();

        RateLimitFilter rateLimitFilter = new RateLimitFilter(hierarchicalRateLimiter, clientInfoExtractor);

        registrationBean.setFilter(rateLimitFilter);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(properties.getFilterOrder() != 0 ? properties.getFilterOrder() : 1);
        registrationBean.setName("rateLimitFilter");

        return registrationBean;
    }

}